home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 51 / Amiga Format CD51 (2000-03-10)(Future Publishing)(GB)[!][issue 2000-04].iso / -in_the_mag- / pdselect / run44 / run.asm < prev    next >
Assembly Source File  |  2000-02-16  |  25KB  |  1,197 lines

  1. ; FILE: Source:run.ASM          REV: 12 --- run with detach
  2. ; History
  3. ;  0      started 5th Jan 2000. loosely based on kickstart 40.68
  4. ;         internal run.
  5. ;  1      works. DETACH/S and QUIET/S not yet functional.
  6. ;  2      wrote forpath & findcommand for DETACH/S.
  7. ;  3      wrote detach routine for DETACH/S. Added STACK/K/N and
  8. ;         PRI/K/N (work for non-detach mode too).
  9. ;  4      6th Jan 2000: DETACH/S: worked a bit on ReadItem() problem,
  10. ;         now it finally works as expected. Made QUIET/S work.
  11. ;  5      DETACH/S: added proper ioerr to findcommand failure, added
  12. ;         consistent error output, uses undocumented negative ioerr
  13. ;         with PrintFault().
  14. ;  6      DETACH/S: won't load executable with E bit clear, now
  15. ;         findcommand should find the command 100% the same as
  16. ;         amigaos shell.
  17. ;  7      DETACH/S: removed Forbid() + FreeVec() hack from pr_ExitCode,
  18. ;         uses AllocEntry() + TC_MEMLIST instead.
  19. ;  8      7th Jan 2000: now DETACH/S creates complete fake CLI
  20. ;         structure.
  21. ;  9      now DETACH/S always adds exitcode to process because it also
  22. ;         clears pr_Flags PRF_FREESEGLIST if pr_CLI.cli_Module gets
  23. ;         cleared by command. this prevents crash if command has
  24. ;         autodetach feature built in. nice.
  25. ;  10     DETACH/S exitcode: hmm, apparently clearing PRF_FREESEGLIST
  26. ;         is not enough, now also clears item 3 from pr_SegList array.
  27. ;         now seems to work properly. froze 44.1.beta1.
  28. ;  11     8th Jan 2000: DETACH/S used to copy PROGDIR: of `run' itself,
  29. ;         caused missing PROGDIR: if `run' was made resident. Now sets
  30. ;         it properly. As a side effect had to create better API for
  31. ;         findcommand, now uses structure to pass things around.
  32. ;  12     27th Jan 2000: DETACH/S failed to create PROGDIR: correctly
  33. ;         if programname had path components. Fixed & changed
  34. ;         findcommand API a bit. froze 44.1 aminet release.
  35. ;
  36.  
  37. ; installation:
  38. ;
  39. ; protect source:run prwed
  40. ; resident run remove
  41. ; resident source:run add
  42.  
  43. ; defaults
  44. MIN_STACK    EQU    512            ; minimum stack allowed
  45. MAX_PRI    EQU    127            ; maximum priority allowed
  46. MIN_PRI    EQU    -128            ; minimum priority allowed
  47. DIR_LEN    EQU    80            ; maximum cli_SetName len
  48. COMMNAME_LEN    EQU    104            ; maximum cli_CommandName len
  49. PROMPT_LEN    EQU    60            ; maximum cli_Prompt len
  50.  
  51. SUBQ1ABS_OPCODE    EQU    $53B9            ; subq.l #1,(abs).l
  52.  
  53.  
  54. ; flags for conditional compiling
  55. USE_TC_MEMLIST    EQU    1
  56.  
  57.  
  58.     include    "exec/lists.i"
  59.     include    "exec/libraries.i"
  60.     include    "exec/memory.i"
  61.     include    "dos/dos.i"
  62.     include    "dos/dosextens.i"
  63.     include    "dos/rdargs.i"
  64.     include    "dos/dostags.i"
  65.  
  66.     include    "exec/exec_lib.i"
  67.     include    "dos/dos_lib.i"
  68.  
  69. call    MACRO
  70.     jsr    (_LVO\1,a6)
  71.     ENDM
  72.  
  73.  
  74.     STRUCTURE stackdata,0
  75.     APTR    sd_execbase
  76.     APTR    sd_dosbase
  77.     APTR    sd_rdargs
  78.     LABEL    sd_args
  79.     LONG    sd_detach
  80.     LONG    sd_quiet
  81.     LONG    sd_stack
  82.     LONG    sd_pri
  83.     APTR    sd_command
  84.     ALIGNLONG
  85.     LABEL    sd_SIZEOF
  86.  
  87.  
  88. ; ---> detach routine
  89.  
  90.     BITDEF    DETACH,USENIL,0
  91.  
  92. ; <--- detach routine
  93.  
  94.  
  95. ; ---> findcommand routine
  96.  
  97.     STRUCTURE fcmd,0
  98.     BPTR    fcmd_seglist        ; in: 0 out: seglist
  99.     LABEL    fcmd_nameptr        ; in: char *
  100.     BPTR    fcmd_homedir        ; out: BPTR
  101.     LONG    fcmd_subqpos        ; in: 0 out: &seg_UC if res, else 0
  102.     APTR    fcmd_internal        ; internal stuff
  103.     LABEL    fcmd_SIZEOF
  104.  
  105. ; <--- findcommand routine
  106.  
  107.  
  108.  
  109. Main    movem.l    d2-d3/d6-d7/a3-a6,-(sp)
  110.  
  111.     moveq    #sd_SIZEOF/4,d0
  112. .clr    clr.l    -(sp)
  113.     subq.l    #1,d0
  114.     bne.b    .clr
  115.     move.l    sp,a5
  116.  
  117.     move.l    (4).w,a6
  118.     moveq    #RETURN_ERROR,d7
  119.     move.l    a6,(a5)
  120.  
  121.     lea    (dosname,pc),a1
  122.     moveq    #39,d0
  123.     call    OpenLibrary
  124.     move.l    d0,(sd_dosbase,a5)
  125.     beq    .cleanup
  126.  
  127.     move.l    (sd_dosbase,a5),a6
  128.  
  129.     lea    (template,pc),a0
  130.     move.l    a0,d1
  131.     lea    (sd_args,a5),a0
  132.     move.l    a0,d2
  133.     moveq    #0,d3
  134.     call    ReadArgs
  135.     move.l    d0,(sd_rdargs,a5)
  136.     bne.b    .argsok
  137.  
  138.     call    IoErr
  139.     move.l    d0,d1
  140.     moveq    #0,d2
  141.     call    PrintFault
  142.     bra    .cleanup
  143. .argsok
  144.  
  145.     ; check priority validity:
  146.     move.l    (sd_pri,a5),d0
  147.     beq.b    .priok
  148.     move.l    d0,a0
  149.     move.l    (a0),d0
  150.     cmp.l    #MAX_PRI,d0
  151.     ble.b    .nottoohigh
  152.     moveq    #MAX_PRI,d0
  153. .nottoohigh    cmp.l    #MIN_PRI,d0
  154.     bge.b    .nottoolow
  155.     moveq    #MIN_PRI,d0
  156. .nottoolow    move.l    d0,(a0)
  157. .priok
  158.     ; check stack validity:
  159.     move.l    (sd_stack,a5),d0
  160.     beq.b    .stackok
  161.     move.l    d0,a0
  162.     move.l    (a0),d0
  163.     cmp.l    #MIN_STACK,d0
  164.     bge.b    .stackok
  165.     move.l    #MIN_STACK,(a0)
  166. .stackok
  167.  
  168.     ; `old way' run or detach?
  169.     tst.l    (sd_detach,a5)
  170.     bne    .detach
  171.  
  172.     ; this code fragment builds fake filehandle
  173.     ; that feeds System() with COMMAND/F argument.
  174.     ; this is the way amigaos does it. hacky ain't it?
  175.     ;
  176.     ; System() will free memory allocated...
  177.     ; could maybe use AllocDosObject DOS_FILEHANDLE ?
  178.     ;
  179.  
  180.     move.l    (sd_command,a5),a4
  181.     move.l    a4,d0
  182.     bne.b    .cmdok
  183.     lea    (nullstr,pc),a4
  184. .cmdok
  185.     moveq    #-1,d6
  186.     move.l    a4,a0
  187. .len    addq.l    #1,d6
  188.     tst.b    (a0)+
  189.     bne.b    .len
  190.  
  191.     moveq    #fh_SIZEOF+14+2,d0
  192.     add.l    d6,d0
  193.     move.l    #MEMF_PUBLIC|MEMF_CLEAR,d1
  194.     move.l    (a5),a6
  195.     call    AllocVec
  196.     tst.l    d0
  197.     beq    .cleanup
  198.  
  199.     move.l    d0,a3
  200.     lea    (fh_SIZEOF,a3),a0
  201.     move.l    a0,d0
  202.     asr.l    #2,d0
  203.     move.l    d0,(fh_Buf,a3)
  204.  
  205.     move.l    d6,d0
  206.     beq.b    .nocopy
  207. .bcopy    move.b    (a4)+,(a0)+
  208.     subq.l    #1,d0
  209.     bne.b    .bcopy
  210. .nocopy
  211.     move.b    #10,(a0)+
  212.     move.b    #10,(a0)
  213.  
  214.     addq.l    #2,d6
  215.     move.l    a3,d2
  216.     move.l    d6,(fh_End,a3)
  217.  
  218.     move.l    (sd_dosbase,a5),a6
  219.     asr.l    #2,d2
  220.  
  221.     move.l    sp,a2
  222.  
  223.     clr.l    -(sp)
  224.     pea    (1).w
  225.     pea    SYS_UserShell
  226.     call    Output
  227.     move.l    d0,-(sp)
  228.     pea    SYS_Output
  229.  
  230.     move.l    d2,-(sp)
  231.     pea    SYS_Input
  232.  
  233.     move.l    (sd_stack,a5),d0
  234.     beq.b    .nostack
  235.     move.l    d0,a0
  236.     move.l    (a0),-(sp)
  237.     pea    NP_StackSize
  238. .nostack
  239.     move.l    (sd_pri,a5),d0
  240.     beq.b    .nopri
  241.     move.l    d0,a0
  242.     move.l    (a0),-(sp)
  243.     pea    NP_Priority
  244. .nopri
  245.     moveq    #0,d1
  246.     move.l    sp,d2
  247.     call    SystemTagList
  248.     move.l    a2,sp
  249.  
  250.     move.l    d0,d7
  251.     addq.l    #1,d0
  252.     bne.b    .cleanup
  253.  
  254.     moveq    #RETURN_ERROR,d7
  255.  
  256. .cleanup    move.l    (sd_dosbase,a5),d0
  257.     beq.b    .nodos
  258.     move.l    d0,a6
  259.     move.l    (sd_rdargs,a5),d1
  260.     beq.b    .no_freeargs
  261.     call    FreeArgs
  262. .no_freeargs    move.l    (sd_dosbase,a5),a1
  263.     move.l    (a5),a6
  264.     call    CloseLibrary
  265. .nodos    lea    (sd_SIZEOF,sp),sp
  266.     move.l    d7,d0
  267.     movem.l    (sp)+,d2-d3/d6-d7/a3-a6
  268.     rts
  269.  
  270.  
  271. .detach    move.l    #$80000000,d1
  272.     move.l    (sd_pri,a5),d0
  273.     beq.b    .use_defpri
  274.     move.l    d0,a0
  275.     move.l    (a0),d1
  276. .use_defpri
  277.     move.l    (sd_stack,a5),d2
  278.     beq.b    .use_defstack
  279.     move.l    d2,a0
  280.     move.l    (a0),d2
  281. .use_defstack
  282.     moveq    #0,d0
  283.     tst.l    (sd_quiet,a5)
  284.     beq.b    .noquiet
  285.     moveq    #DETACHF_USENIL,d0
  286. .noquiet
  287.     move.l    (sd_command,a5),a0
  288.     bsr.b    detach            ; has internal check for null a0
  289.     tst.l    d0
  290.     beq.b    .cleanup
  291.     moveq    #RETURN_OK,d7
  292.     bra.b    .cleanup
  293.  
  294.  
  295. ; detach - run given command as background process with fake cli
  296. ; structure.
  297. ;
  298. ;  IN: a0=char *commandline (will be modified)
  299. ;      a6=dosbase
  300. ;      d0=flags
  301. ;      d1=priority, $80000000 = use default
  302. ;      d2=stacksize, 0 = use default
  303. ; OUT: d0=success
  304. ;
  305. detach    movem.l    d0-d7/a0-a6,-(sp)
  306.     move.l    d0,d6
  307.     move.l    sp,a5
  308.     clr.l    (sp)
  309.     move.l    (4).w,d7
  310.  
  311.     move.l    a0,d0            ; null commandline?
  312.     beq    .exit            ; eek, quit!
  313.     tst.b    (a0)
  314.     beq    .exit            ; eek, quit!
  315.  
  316.     moveq    #0,d4
  317.     moveq    #0,d5
  318.     IFNE    USE_TC_MEMLIST
  319.     move.w    #-1,a4
  320.     ELSE
  321.     sub.l    a4,a4
  322.     ENDC
  323.  
  324.     ; get commandline len
  325.     move.l    (8*4,sp),a0        ; get a0 from stack
  326.     moveq    #-1,d0
  327. .len    addq.l    #1,d0
  328.     tst.b    (a0)+
  329.     bne.b    .len
  330.  
  331.     ; build CSource structure to stack
  332.     lea    (-COMMNAME_LEN,sp),sp    ; storage for commandname
  333.     clr.b    (sp)            ; nullterminate! (for .argfail)
  334.     move.l    sp,d1            ; buffer
  335.     clr.l    -(sp)            ; CS_CurChr
  336.     move.l    d0,-(sp)        ; CS_Length
  337.     move.l    (8*4,a5),-(sp)        ; CS_Buffer (get a0 from stack)
  338.  
  339.     moveq    #COMMNAME_LEN-1,d2    ; maxchars
  340.     move.l    sp,d3            ; struct CSource *
  341.     call    ReadItem
  342.  
  343.     moveq    #0,d3            ; d3=homedir lock ptr!
  344.  
  345.     move.l    (sp)+,a0        ; CS_Buffer
  346.     move.l    (sp)+,d1        ; CS_Length
  347.     add.l    (sp)+,a0        ; add CS_CurChr
  348.  
  349.     tst.l    d0
  350.     bmi    .argfail
  351.  
  352.     ; skip some chars if needed, needed because ReadItem()
  353.     ; does UnGetC... stupid.
  354.  
  355.     subq.l    #2,d1            ; must have at least one char
  356.     bmi.b    .singlearg
  357.     cmp.b    #' ',(-1,a0)
  358.     beq.b    .noskip
  359.     addq.l    #1,a0
  360.     bra.b    .noskip
  361. .singlearg    tst.b    (a0)+            ; make a0 point nullchar
  362.     bne.b    .singlearg
  363.     subq.l    #1,a0
  364. .noskip
  365.  
  366.     ; a0 = after first param = command arguments.
  367.     ; quite neat eh? OS rules ;)
  368.  
  369.     ; lf + null terminate a0 string,
  370.     ; this is really needed, NP_Arguments &
  371.     ; ReadArgs() require this
  372.     move.l    (8*4,a5),a1        ; get a0 from stack
  373. .copy    move.b    (a0)+,(a1)+
  374.     bne.b    .copy
  375.     move.b    #10,(-1,a1)
  376.     move.b    #0,(a1)
  377.  
  378.     ; if USENIL flag is set don't open console:
  379.     ; filehandles, but use default nil: i/o
  380.  
  381.     btst    #DETACHB_USENIL,d6
  382.     bne.b    .use_nil1
  383.  
  384.     lea    (.conname,pc),a2
  385.     move.l    a2,d1
  386.     move.l    #MODE_NEWFILE,d2
  387.     call    Open
  388.     move.l    d0,d5
  389.     beq    .filefail
  390.     move.l    a2,d1
  391.     ;move.l    #MODE_NEWFILE,d2
  392.     call    Open
  393.     move.l    d0,d4
  394.     beq    .filefail
  395. .use_nil1
  396.  
  397.     ; build taglist for CreateNewProc to stack
  398.  
  399.     clr.l    -(sp)
  400.     move.l    (8*4,a5),-(sp)        ; get a0 from stack
  401.     pea    NP_Arguments
  402.     pea    (-COMMNAME_LEN,a5)    ; commandname
  403.     pea    NP_Name
  404.  
  405.     ; find command seglist, uses findcommand subroutine
  406.  
  407.     ; build findcommand structure to stack
  408.     subq.l    #4,sp            ; fcmd_internal
  409.     clr.l    -(sp)            ; fcmd_subqpos
  410.     pea    (-COMMNAME_LEN,a5)    ; in: fcmd_nameptr / out: fcmd_homedir
  411.     clr.l    -(sp)            ; fcmd_seglist
  412.     move.l    sp,a0
  413.     bsr    findcommand
  414.     move.l    (sp)+,a3        ; get fcmd_seglist
  415.     move.l    (sp)+,d1        ; get fcmd_homedir
  416.     move.l    (sp)+,a2        ; get fcmd_subqpos
  417.     addq.l    #4,sp            ; pop fcmd_internal
  418.  
  419.     tst.l    d0
  420.     beq    .nocommand
  421.  
  422.     move.l    d1,d3            ; d1=fcmd_homedir
  423.  
  424.     ; make PROGDIR: work...
  425.     move.l    d3,-(sp)
  426.     pea    NP_HomeDir
  427.  
  428.     ; if the command found was (not internal) resident we
  429.     ; must prepare ourselves to decrement its seg_UC
  430.     ; after executing it. this requires some hacking
  431.     ; namely use of NP_ExitCode to pass code to be run
  432.     ; after program termination and some way to free the
  433.     ; memory fragment allocated for that code.
  434.     ;
  435.     ; there are two ways to handle the memory freeing,
  436.     ; either Forbid() & free the memory in exitcode
  437.     ; itself or use task TCB's TC_MEMLIST to free it.
  438.     ; latter is more OS legal, but requires sorrounding
  439.     ; CreateNewProc() with Forbid()/Permit() pair.
  440.     ;
  441.     ; but then, we need to forbid there anyways, because
  442.     ; of pr_CLI faking so USE_TC_MEMLIST method is better.
  443.     ;
  444.     ; this exitcode also handles cli_Module=NULL seglist
  445.     ; cutting, this prevents potential problems if
  446.     ; command has some autodetach logic built in.
  447.  
  448.     exg    d7,a6
  449.  
  450.     IFNE    USE_TC_MEMLIST
  451.  
  452.     ; build MemEntry to stack
  453.     pea    (exitcode_SIZEOF).w
  454.     pea    (MEMF_PUBLIC).w        Entry #0
  455.     pea    (1).w            Number of entries (longword zeropadded)
  456.     lea    (-(LN_SIZE-2),sp),sp    Reserve space for list node (-2 = padding...)
  457.     move.l    sp,a0
  458.     call    AllocEntry
  459.     lea    ((LN_SIZE-2)+(3*4),sp),sp
  460.     exg    d7,a6
  461.     tst.l    d0
  462.     bmi    .nomem
  463.  
  464.     move.l    d0,a4
  465.     move.l    (ML_ME+0*ME_SIZE,a4),a1
  466.  
  467.     ELSE
  468.  
  469.     moveq    #exitcode_SIZEOF,d0
  470.     moveq    #MEMF_PUBLIC,d1
  471.     call    AllocVec
  472.     exg    d7,a6
  473.     tst.l    d0
  474.     beq    .nomem
  475.     move.l    d0,a4
  476.     move.l    d0,a1
  477.  
  478.     ENDC
  479.  
  480.     ; copy the exitcode to newly allocated memory:
  481.  
  482.     exg    d7,a6
  483.     lea    (.exitcode,pc),a0
  484.     moveq    #exitcode_SIZEOF,d0
  485.     call    CopyMem
  486.  
  487.     ; if we need to decrement seg_UC add subq instruction:
  488.     move.l    a2,d0
  489.     beq.b    .no_subqinst
  490.     IFNE    USE_TC_MEMLIST
  491.     move.l    (ML_ME+0*ME_SIZE,a4),a0
  492.     ;lea    (.subqaddr-.exitcode,a0),a0
  493.     ELSE
  494.     ;lea    (.subqaddr-.exitcode,a4),a0
  495.     move.l    a4,a0
  496.     ENDC
  497.     move.w    #SUBQ1ABS_OPCODE,(a0)+
  498.     move.l    a2,(a0)
  499. .no_subqinst
  500.  
  501.     ; we just built code to be executed so better clear
  502.     ; CPU caches...
  503.     call    CacheClearU
  504.     exg    d7,a6
  505.  
  506.     ; stuff exitcode
  507.     IFNE    USE_TC_MEMLIST
  508.     move.l    (ML_ME+0*ME_SIZE,a4),-(sp)
  509.     ELSE
  510.     move.l    a4,-(sp)
  511.     ENDC
  512.     pea    NP_ExitCode
  513.  
  514.  
  515.     ; ask OS to free the seglist when done (default)
  516.  
  517.     pea    (1).w
  518.     pea    NP_FreeSeglist
  519.  
  520.     ; pass the seglist pointer
  521.  
  522.     move.l    a3,-(sp)
  523.     bpl.b    .segptok
  524.     ; seglist pointer was negative so we must negate it to
  525.     ; get real pointer. this also indicates that this seglist
  526.     ; should not be unloadseg'd when done so clear ti_Data of
  527.     ; NP_FreeSeglist tag.
  528.     neg.l    (sp)
  529.     clr.l    (8,sp)            ; clear ti_Data of NP_FreeSeglist
  530. .segptok    pea    NP_Seglist
  531.  
  532.  
  533.     ; if we were given a priority, stuff tag indicating it
  534.  
  535.     move.l    (1*4,a5),d0        ; get d1 from stack
  536.     cmp.l    #$80000000,d0
  537.     beq.b    .use_defpri
  538.     move.l    d0,-(sp)
  539.     pea    NP_Priority
  540. .use_defpri
  541.  
  542.     ; put NP_StackSize tag.
  543.     ; if d2 was <>0 then use that value as stack size
  544.     move.l    (2*4,a5),-(sp)        ; get d2 from stack
  545.     bne.b    .notcli
  546.     ; so d2 was zero then, lets try to peek out default
  547.     ; value to use. strategy:
  548.     ; 1) if CLI process get cli_DefaultStack
  549.     ; 2) not CLI process: use pr_StackSize or 4000,
  550.     ;    whichever is larger
  551.     exg    d7,a6
  552.     sub.l    a1,a1
  553.     call    FindTask
  554.     exg    d7,a6
  555.     move.l    d0,a0
  556.     move.l    (pr_StackSize,a0),d0
  557.     cmp.l    #4000,d0
  558.     bhs.b    .prstackok
  559.     move.l    #4000,d0
  560. .prstackok    move.l    d0,(sp)
  561.     call    Cli
  562.     tst.l    d0
  563.     beq.b    .notcli
  564.     move.l    d0,a0
  565.     move.l    (cli_DefaultStack,a0),d0
  566.     lsl.l    #2,d0            ; must *4
  567.     move.l    d0,(sp)
  568. .notcli    pea    NP_StackSize
  569.  
  570.     ; put NP_Output and NP_Input tags, unless USENIL flag
  571.     btst    #DETACHB_USENIL,d6
  572.     bne.b    .use_nil2
  573.     move.l    d5,-(sp)
  574.     pea    NP_Output
  575.     move.l    d4,-(sp)
  576.     pea    NP_Input
  577. .use_nil2
  578.  
  579.     ; allocate the fake CLI structure
  580.     clr.l    -(sp)
  581.     pea    (DIR_LEN).w
  582.     pea    ADO_DirLen        ; size in bytes for current dir buffer
  583.     pea    (COMMNAME_LEN).w
  584.     pea    ADO_CommNameLen        ; size in bytes for command name buffer
  585.     pea    (PROMPT_LEN).w
  586.     pea    ADO_PromptLen        ; size in bytes for the prompt buffer
  587.     move.l    sp,d2
  588.     moveq    #DOS_CLI,d1
  589.     call    AllocDosObject
  590.     lea    (7*4,sp),sp        ; pop stack
  591.     move.l    d0,d2
  592.     beq    .nocli
  593.  
  594.  
  595.     ; also, for completeness, we need to poke in some
  596.     ; standard values to CLI structure. this ensures
  597.     ; that program using them will not choke.
  598.  
  599.     movem.l    d2-d3/a2,-(sp)        ; must store d2-d3/a2 for .procfail!
  600.     move.l    d2,a2
  601.     lea    (-DIR_LEN,sp),sp    ; temp string storage
  602.  
  603.     ; set cli_SetName:
  604.     move.l    sp,d1
  605.     moveq    #DIR_LEN-1,d3
  606.     call    GetCurrentDirName
  607.     move.l    sp,a0
  608.     move.l    (cli_SetName,a2),a1
  609.     bsr    .cstr2bstr
  610.  
  611.     ; set cli_CommandName:
  612.     lea    (-COMMNAME_LEN,a5),a0
  613.     move.l    (cli_CommandName,a2),a1
  614.     bsr    .cstr2bstr
  615.  
  616.     ; copy parent's prompt:
  617.     move.l    sp,d1
  618.     moveq    #PROMPT_LEN-1,d2
  619.     call    GetPrompt
  620.     move.l    sp,a0
  621.     move.l    (cli_Prompt,a2),a1
  622.     bsr    .cstr2bstr
  623.  
  624.     ;cli_CommandFile will be nullstr.
  625.  
  626.     ; default defaultstack :)
  627.     move.l    #4096/4,(cli_DefaultStack,a2)
  628.     ; copy parent's cli_DefaultStack & cli_FailLevel:
  629.     call    Cli
  630.     tst.l    d0
  631.     beq.b    .noparent
  632.     move.l    d0,a0
  633.  
  634.     move.l    (cli_DefaultStack,a0),(cli_DefaultStack,a2)
  635.     move.l    (cli_FailLevel,a0),(cli_FailLevel,a2)
  636.  
  637.     ; copy parent's cli_CommandDir
  638.     move.l    (cli_CommandDir,a0),d0
  639.     bsr    copycommanddir
  640.     move.l    d0,(cli_CommandDir,a2)
  641. .noparent
  642.     ; set cli_Module:
  643.     move.l    a3,(cli_Module,a2)
  644.     bpl.b    .segptok2
  645.     neg.l    (cli_Module,a2)
  646. .segptok2
  647.  
  648.     lea    (DIR_LEN,sp),sp        ; pop temp string storage
  649.     movem.l    (sp)+,d2-d3/a2
  650.  
  651.  
  652.     ; must forbid because we change newly created
  653.     ; process before it will be run.
  654.     exg    d7,a6
  655.     call    Forbid
  656.     exg    d7,a6
  657.  
  658.     ; create the process!
  659.     move.l    sp,d1
  660.     call    CreateNewProc
  661.  
  662.     ; if failed, get out and free everything we
  663.     ; allocated.
  664.     tst.l    d0
  665.     beq.b    .procfail
  666.  
  667.     ; if we're using USE_TC_MEMLIST exitcode strategy
  668.     ; we must now link it to task's TC_MEMENTRY in order
  669.     ; it to get FreeEntry()'d on RemTask().
  670.  
  671.     move.l    d0,a2            ; can trash a2 here
  672.  
  673.     IFNE    USE_TC_MEMLIST
  674.     lea    (TC_MEMENTRY,a2),a0
  675.     move.l    a4,a1
  676.     ADDHEAD
  677.     ENDC
  678.  
  679.     ; now we only need to poke in the fake CLI structure
  680.     ; for the process (set BPTR(cli) to pr_CLI) and ask
  681.     ; process to free it when it will exit (set
  682.     ; PRF_FREECLI in pr_Flags).
  683.  
  684.     move.l    d2,a0
  685.  
  686.     ; set cli_StandardInput & cli_CurrentInput:
  687.     move.l    (pr_CIS,a2),(cli_StandardInput,a0)
  688.     move.l    (pr_CIS,a2),(cli_CurrentInput,a0)
  689.  
  690.     ; set cli_CurrentOutput & cli_StandardOutput:
  691.     move.l    (pr_COS,a2),(cli_StandardOutput,a0)
  692.     move.l    (pr_COS,a2),(cli_CurrentOutput,a0)
  693.  
  694.     lsr.l    #2,d2            ; APTR->BPTR
  695.     move.l    d2,(pr_CLI,a2)        ; set pr_CLI
  696.     or.w    #PRF_FREECLI,(pr_Flags+2,a2)    ; set PRF_FREECLI
  697.  
  698.  
  699.     exg    d7,a6
  700.     call    Permit            ; let it run!
  701.  
  702.     addq.l    #1,(a5)            ; return success
  703.  
  704. .exit    move.l    a5,sp
  705.     movem.l    (sp)+,d0-d7/a0-a6
  706.     rts
  707.  
  708.  
  709. .procfail    exg    d7,a6
  710.     call    Permit
  711.     exg    d7,a6
  712.     moveq    #4,d1            ;DOS_CLI
  713.     ;move.l    d2,d2
  714.     call    FreeDosObject
  715.  
  716. .nocli
  717.     IFNE    USE_TC_MEMLIST
  718.     move.l    a4,d0
  719.     bmi.b    .nomem
  720.     exg    d7,a6
  721.     move.l    a4,a0
  722.     call    FreeEntry
  723.     ELSE
  724.     move.l    a4,d0
  725.     beq.b    .nomem
  726.     exg    d7,a6
  727.     move.l    a4,a1
  728.     call    FreeVec
  729.     ENDC
  730.     exg    d7,a6
  731. .nomem
  732.     move.l    a2,d0
  733.     beq.b    .nosub
  734.     subq.l    #1,(a2)            ; decrement seg_UC
  735. .nosub    move.l    a3,d1            ; unload the segment
  736.     bmi.b    .nounload        ; *only* when needed
  737.     call    UnLoadSeg
  738. .nounload
  739.  
  740. .nocommand
  741. .filefail
  742. .argfail    call    IoErr
  743.     move.l    d0,d2
  744.     move.l    d3,d1
  745.     beq.b    .nol
  746.     call    UnLock
  747. .nol    move.l    d4,d1
  748.     beq.b    .noc1
  749.     call    Close
  750. .noc1    move.l    d5,d1
  751.     beq.b    .noc2
  752.     call    Close
  753. .noc2
  754.     cmp.l    #ERROR_OBJECT_NOT_FOUND,d2
  755.     bne.b    .othererr
  756.  
  757.     ; uses undocumented feature of PrintFault() here.
  758.     ; if you give it negative value it outputs some
  759.     ; predefined string from internal table.
  760.     ; locale.library will patch this table with current
  761.     ; language's strings. this way we stay 100% language
  762.     ; independent and don't need separate locale support.
  763.  
  764.     moveq    #-121,d1        ; "Unknown command" (in english)
  765.     lea    (-COMMNAME_LEN,a5),a0
  766.     move.l    a0,d2
  767.     bra.b    .pfault
  768. .othererr
  769.     move.l    d2,d1
  770.     moveq    #0,d2
  771. .pfault    call    PrintFault
  772.     bra.b    .exit
  773.  
  774.  
  775.     ; copy str to bstr & fix bstr len
  776. .cstr2bstr    move.l    a2,d0
  777.     add.l    a1,a1
  778.     add.l    a1,a1
  779.     move.l    a1,a2
  780.     st    (a1)+            ; put -1 to count
  781. .cs2bsl    addq.b    #1,(a2)            ; increment count
  782.     move.b    (a0)+,(a1)+        ; copy chars, until zero
  783.     bne.b    .cs2bsl
  784.     move.l    d0,a2
  785.     rts
  786.  
  787.  
  788. ;  IN: d0=rc
  789. ;      d1=exitdata
  790. ;      a6=execbase (documented?)
  791. ; OUT: d0=rc
  792.  
  793. .exitcode
  794. .subqaddr    dc.w    $6004,$dead,$c0de
  795.     movem.l    d0/a6,-(sp)
  796.     move.l    (4).w,a6
  797.  
  798.     sub.l    a1,a1
  799.     call    FindTask
  800.     move.l    d0,a1
  801.  
  802.     ; pr_CLI can be null if someone has
  803.     ; released it. we must prepare.
  804.     move.l    (pr_CLI,a1),d0
  805.     beq.b    .ec_nocli
  806.     lsl.l    #2,d0
  807.     move.l    d0,a0
  808.     tst.l    (cli_Module,a0)
  809.     bne.b    .ec_gotmodule
  810.     and.w    #~PRF_FREESEGLIST,(pr_Flags+2,a1)
  811.     move.l    (pr_SegList,a1),d0    ; get BPTR to array of seglist used...
  812.     lsl.l    #2,d0            ; BPTR->APTR
  813.     move.l    d0,a0
  814.     clr.l    (12,a0)            ; really prevent unloading!
  815. .ec_gotmodule
  816. .ec_nocli
  817.     IFEQ    USE_TC_MEMLIST
  818.     call    Forbid            ; we'll free ourself...
  819.  
  820.     lea    (.exitcode,pc),a1    ; set us free !-)
  821.     call    FreeVec            ; return + run rest of the code
  822.                     ; in Forbid() state. RemTask(0)
  823.                     ; will end this soon... :)
  824.     ENDC
  825.     movem.l    (sp)+,d0/a6
  826.     rts
  827. exitcode_SIZEOF    EQU    *-.exitcode
  828.  
  829. .conname    dc.b    'console:',0
  830.     CNOP    0,2
  831.  
  832.  
  833. ; copycommanddir - create copy of cli_CommandDir
  834. ;
  835. ;  IN: d0=BPTR commanddir
  836. ;      a6=dosbase
  837. ; OUT: d0=BPTR newcommanddir
  838. ;
  839. copycommanddir    movem.l    d7/a3-a6,-(sp)
  840.     clr.l    -(sp)
  841.     move.l    (4).w,d7
  842.  
  843.     move.l    d0,a5
  844.     move.l    sp,a4
  845.     bra.b    .gocopy
  846.  
  847. .copy    exg    d7,a6
  848.     moveq    #8,d0
  849.     moveq    #MEMF_PUBLIC,d1
  850.     call    AllocVec
  851.     tst.l    d0
  852.     beq.b    .exit
  853.     exg    d7,a6
  854.     move.l    d0,a3
  855.     move.l    (4,a5),d1        ; from->lock
  856.     call    DupLock
  857.     move.l    a3,d1
  858.     lsr.l    #2,d1
  859.     move.l    d1,(a4)            ; pred->succ=BPTR(this)
  860.     move.l    a3,a4            ; pred=this
  861.     clr.l    (a3)+            ; this->succ=NULL
  862.     move.l    d0,(a3)            ; this->lock=lock
  863.     move.l    (a5),a5            ; from=from->succ
  864. .gocopy    add.l    a5,a5            ; from=APTR(from)
  865.     add.l    a5,a5
  866.     move.l    a5,d0
  867.     bne.b    .copy
  868. .exit    movem.l    (sp)+,d0/d7/a3-a6
  869.     rts
  870.  
  871.  
  872.     STRUCTURE data,0
  873.     APTR    d_seglistptr
  874.     LABEL    d_nameptr
  875.     APTR    d_homedir
  876.     APTR    d_subqpos
  877.     APTR    d_fib
  878.     LABEL    data_SIZEOF
  879.  
  880.  
  881. ; findcommand - find command and return its seglist, scans resident
  882. ; list first, then shell path(s).
  883. ;
  884. ;  IN: a0=struct fcmd *findcommand,
  885. ;         fcmd_seglist  = 0
  886. ;         fcmd_nameptr  = char *commandname, command name to find
  887. ;         fcmd_subqpos  = 0
  888. ;      a6=dosbase
  889. ; OUT: d0=success, if succeeded structure passed in is filled:
  890. ;      a0=struct fcmd *findcommand,
  891. ;         fcmd_seglist  = BPTR seglist, if positive call UnLoadSeg
  892. ;                         for it when done.
  893. ;         fcmd_homedir  = BPTR lock, MUST be UnLock()ed when done!
  894. ;                         NULL for resident cmds.
  895. ;         fcmd_subqpos  = ULONG *subpos, if <>0 must decrement 1 from
  896. ;                         longword pointed when command has finished
  897. ;                         (this is resident command usecount).
  898. ;
  899. ;      NOTE: if findcommand fails, all fields are zeroed and ioerr
  900. ;      will be set to ERROR_OBJECT_NOT_FOUND.
  901. ;
  902. findcommand    movem.l    d2-d7/a0/a2-a6,-(sp)
  903.     move.l    a0,a5
  904.     move.l    (4).w,d7
  905.  
  906.     ; we need FileInfoBlock for examine...
  907.     moveq    #DOS_FIB,d1
  908.     moveq    #0,d2
  909.     call    AllocDosObject
  910.     move.l    d0,(d_fib,a5)
  911.     beq    .nofib
  912.  
  913.  
  914.     ; first check if command has any path elements
  915.     ; in its name. if it has then split directory and
  916.     ; file names, and try to load the command.
  917.     ; If succeeds, progdir is the PathPart() of the
  918.     ; path.
  919.  
  920.     move.l    (d_nameptr,a5),d2
  921.     move.l    d2,d1
  922.     call    PathPart
  923.     cmp.l    d0,d2
  924.     beq.b    .nofix
  925.  
  926.     ; ok. it does have path elements.
  927.  
  928.     move.l    d0,a2
  929.  
  930.     move.l    d0,d1
  931.     call    FilePart
  932.     move.l    (d_nameptr,a5),d4
  933.     move.l    d0,(d_nameptr,a5)
  934.  
  935.     move.b    (a2),d6
  936.     clr.b    (a2)            ; cut filename
  937.     move.l    d4,d1
  938.     moveq    #ACCESS_READ,d2        ; note: d2<>0 !
  939.     call    Lock
  940.     move.b    d6,(a2)            ; fix filename
  941.     move.l    d0,d3
  942.     beq.b    .nopath
  943.  
  944.     ; d0=lock, a1=data, a6=dosbase
  945.     move.l    a5,a1
  946.     bsr    .findroutine
  947.     move.l    d0,d2
  948.  
  949.     ; cleanup...
  950.     move.l    d3,d1
  951.     call    UnLock
  952.  
  953.     ; don't try to fix d_nameptr here!
  954.  
  955.     tst.l    d2
  956.     beq    .exit            ; found it! quit
  957.  
  958. .nopath
  959.     move.l    d4,(d_nameptr,a5)
  960. .nofix
  961.  
  962.     ; try to find command from resident list
  963.  
  964.  
  965.     exg    d7,a6
  966.     call    Forbid
  967.     exg    d7,a6
  968.  
  969.     ; first try system segments...
  970.     moveq    #1,d3            ; system segments
  971.     bsr.b    .findseg
  972.  
  973.     tst.l    (a5)            ; found seglist?
  974.     bne.b    .foundit        ; yeah, exit
  975.  
  976.     ; we didn't find it from system segment list, try
  977.     ; normal segment list then...
  978.  
  979.     moveq    #0,d3            ; normal segments
  980.     bsr.b    .findseg
  981. .foundit
  982.     exg    d7,a6
  983.     call    Permit
  984.     exg    d7,a6
  985.  
  986.     tst.l    (a5)            ; found seglist?
  987.     bne.b    .exit            ; yeah, exit
  988.  
  989.     ; ok, so we could not find command from resident list,
  990.     ; lets try to find it somewhere within shell path(s)...
  991.     ; (uses forpath subroutine here)
  992.  
  993.     lea    (.findroutine,pc),a0    ; routine
  994.     move.l    a5,a1            ; data
  995.     bsr    forpath            ; do it!
  996.  
  997.     tst.l    (a5)            ; got seglist?
  998.     bne.b    .exit            ; yep, quit
  999.  
  1000.     ; could not find command, set ioerr accordingly
  1001.     move.l    #ERROR_OBJECT_NOT_FOUND,d1
  1002.     call    SetIoErr
  1003.  
  1004. .exit
  1005.     move.l    (d_fib,a5),d2        ; get fib
  1006.     beq.b    .nofib
  1007.     moveq    #DOS_FIB,d1
  1008.     call    FreeDosObject
  1009. .nofib
  1010.     move.l    (a5),d0            ; return success flag
  1011.     bne.b    .exitok
  1012.  
  1013.     ; call failed, make sure fcmd structure is zeroed:
  1014.     clr.l    (fcmd_homedir,a5)
  1015.     clr.l    (fcmd_subqpos,a5)
  1016. .exitok
  1017.     movem.l    (sp)+,d2-d7/a0/a2-a6
  1018.     rts
  1019.  
  1020.  
  1021. .findseg    move.l    (fcmd_nameptr,a5),d1
  1022.     moveq    #0,d2
  1023.     call    FindSegment
  1024.     tst.l    d0
  1025.     beq.b    .fs_no
  1026.  
  1027.     move.l    d0,a0
  1028.     addq.l    #seg_UC,a0
  1029.  
  1030.     cmp.l    #CMD_DISABLED,(a0)    ; disabled internal command?
  1031.     beq.b    .fs_no            ; yeah, don't use this!
  1032.  
  1033.     move.l    (seg_Seg-seg_UC,a0),(a5) ; get seglist
  1034.     neg.l    (a5)            ; mark non-UnLoadSeg()
  1035.  
  1036.     ; resident cmd has no home dir!
  1037.     clr.l    (fcmd_homedir,a5)
  1038.  
  1039.     tst.l    (a0)            ; seg_UC negative?
  1040.     bmi.b    .fs_no            ; yeah, don't increment
  1041.     addq.l    #1,(a0)            ; increment usecount!
  1042.     move.l    a0,(fcmd_subqpos,a5)    ; set seg_UC ptr
  1043. .fs_no    rts
  1044.  
  1045.  
  1046.     ; this routine checks one path element for
  1047.     ; command.
  1048. .findroutine    movem.l    d2-d4/a2,-(sp)
  1049.     ; d0=lock, a1=data, a6=dosbase
  1050.     move.l    a1,a2
  1051.  
  1052.     ; change currentdir
  1053.     move.l    d0,d1
  1054.     call    CurrentDir
  1055.     move.l    d0,d3
  1056.  
  1057.     ; try to get a lock
  1058.     move.l    (d_nameptr,a2),d1
  1059.     moveq    #ACCESS_READ,d2
  1060.     call    Lock
  1061.     move.l    d0,d4
  1062.     beq.b    .fr_nolock
  1063.  
  1064.     ; examine the lock
  1065.     move.l    d4,d1
  1066.     move.l    (d_fib,a2),d2
  1067.     call    Examine
  1068.     tst.l    d0
  1069.     beq.b    .fr_bad
  1070.  
  1071.     ; must have e bit clear (read: set)
  1072.     move.l    (d_fib,a2),a0
  1073.     btst    #FIBB_EXECUTE,(fib_Protection+3,a0)
  1074.     bne.b    .fr_bad
  1075.  
  1076.     ; try to load as executable
  1077.     move.l    (d_nameptr,a2),d1
  1078.     call    LoadSeg
  1079.     move.l    d0,(a2)            ; d_seglistptr
  1080. .fr_bad
  1081.     move.l    d4,d1
  1082.     call    UnLock
  1083. .fr_nolock
  1084.     ; change back to old dir
  1085.     move.l    d3,d1
  1086.     call    CurrentDir
  1087.     move.l    d0,d1            ; d1=path lock
  1088.  
  1089.     ; found it? (d_seglistptr)
  1090.     moveq    #1,d0            ; default: continue
  1091.     tst.l    (a2)
  1092.     beq.b    .fr_exit        ; nope!
  1093.  
  1094.     ; d1=lock
  1095.     call    DupLock
  1096.     move.l    d0,(d_homedir,a2)    ; return homedir!
  1097.     moveq    #0,d0            ; terminate
  1098. .fr_exit
  1099.     movem.l    (sp)+,d2-d4/a2
  1100.     rts
  1101.  
  1102.  
  1103. ; forpath - call subroutine for each path element of process,
  1104. ; if there is no CLI structure for process uses standard paths
  1105. ; currentdir and c:.
  1106. ;
  1107. ;  IN: a0=function to call
  1108. ;      a1=args to function
  1109. ;      a6=dosbase
  1110. ; OUT: d0=number of path elements encounted
  1111.  
  1112. ; function is called with:
  1113. ;  IN: a0=pointer to self
  1114. ;      a1=args to function
  1115. ;      a6=dosbase
  1116. ;      d0=lock of this path
  1117. ; OUT: d0=zero will break out from loop
  1118. ;
  1119. forpath    movem.l    d1-d7/a0-a6,-(sp)
  1120.     moveq    #0,d7
  1121.  
  1122.     moveq    #0,d1
  1123.     call    CurrentDir
  1124.     move.l    d0,d2
  1125.     move.l    d0,d1
  1126.     call    CurrentDir
  1127.  
  1128.     move.l    d2,d0
  1129.     movem.l    (7*4,sp),a0-a1
  1130.     movem.l    d7/a6,-(sp)
  1131.     jsr    (a0)
  1132.     movem.l    (sp)+,d7/a6
  1133.     tst.l    d0
  1134.     beq.b    .exit
  1135.  
  1136.     addq.l    #1,d7
  1137.  
  1138.     call    Cli
  1139.     tst.l    d0
  1140.     beq.b    .nocli
  1141.  
  1142.     move.l    d0,a2
  1143.     move.l    (cli_CommandDir,a2),d0
  1144.     beq.b    .nocli
  1145.  
  1146.     lsl.l    #2,d0
  1147.     move.l    d0,a2
  1148.  
  1149.     movem.l    (7*4,sp),a0-a1
  1150.  
  1151. .more    move.l    (4,a2),d0        ;lock
  1152.     movem.l    d7/a0-a2/a6,-(sp)
  1153.     jsr    (a0)
  1154.     movem.l    (sp)+,d7/a0-a2/a6
  1155.     tst.l    d0
  1156.     beq.b    .exit
  1157.  
  1158.     addq.l    #1,d7
  1159.  
  1160.     move.l    (a2),d0            ;next
  1161.     lsl.l    #2,d0
  1162.     move.l    d0,a2
  1163.     bne.b    .more
  1164.  
  1165. .nocli    lea    (.stdpath,pc),a0
  1166.     move.l    a0,d1
  1167.     moveq    #ACCESS_READ,d2
  1168.     call    Lock
  1169.     move.l    d0,d6
  1170.     beq.b    .exit
  1171.  
  1172.     movem.l    (7*4,sp),a0-a1
  1173.     movem.l    d6-d7/a6,-(sp)
  1174.     jsr    (a0)
  1175.     movem.l    (sp)+,d6-d7/a6
  1176.     tst.l    d0
  1177.     beq.b    .nc_exit
  1178.  
  1179.     addq.l    #1,d7
  1180.  
  1181. .nc_exit    move.l    d6,d1
  1182.     call    UnLock
  1183.  
  1184. .exit    move.l    d7,d0
  1185.     movem.l    (sp)+,d1-d7/a0-a6
  1186.     rts
  1187.  
  1188. .stdpath    dc.b    'c:',0
  1189.     CNOP    0,2
  1190.  
  1191.  
  1192.     dc.b    '$VER: run 44.1 (27.1.00)',0
  1193.  
  1194. dosname    dc.b    'dos.library',0
  1195. nullstr    EQU    *-1
  1196. template    dc.b    'DETACH/S,QUIET/S,STACK/K/N,PRI/K/N,COMMAND/F',0
  1197.